'/
' ProjectName
' 
' =========================================================================
' 
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
' 
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' GNU General Public License for more details.
' 
' You should have received a copy of the GNU General Public License
' along with this program.  If not, see <http://www.gnu.org/licenses/>.
'/

type Sound extends Base

	'// -------------------------------------------------------------------------------------------------------------
	'// Create, setup and return a sound object.
	'// -------------------------------------------------------------------------------------------------------------
	function create:Sound(url:string)
	
		local snd:Sound = new Sound;
		
		snd.m_sample = loadAudioSample(url);
		if (not snd.m_sample) then
		
			sGUI.error("Failed to load sound ~q" + url + "~q.");
			return null;
		
		end if
		
		snd.m_url = url;
		
		alGenBuffers(1, varptr(snd.m_buffer));
		
		snd.m_samples = snd.m_sample.samples;
		snd.m_freq = snd.m_sample.hertz;
		
		select (snd.m_sample.format)
		
			case SF_MONO8      snd.m_format = AL_FORMAT_MONO8;
			case SF_MONO16LE   snd.m_format = AL_FORMAT_MONO16;
			case SF_MONO16BE   snd.m_format = AL_FORMAT_MONO16;
			case SF_STEREO8    snd.m_format = AL_FORMAT_MONO8;
			case SF_STEREO16LE snd.m_format = AL_FORMAT_MONO16;
			case SF_STEREO16BE snd.m_format = AL_FORMAT_MONO16;
			default
				sGUI.error("Invalid sound format of file ~q" + url + "~q.");
				return null;
		
		end select
		
		snd.m_length = snd.m_sample.length * bytespersample[snd.m_sample.format];
		
		alBufferData(snd.m_buffer, snd.m_format, snd.m_samples, snd.m_length, snd.m_freq);
		
		alGenSources(1, varptr(snd.m_source));
		alSourcei(snd.m_source, AL_BUFFER, snd.m_buffer);
		
		return snd;
	
	end function
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the length of the sound (in samples).
	'// -------------------------------------------------------------------------------------------------------------
	method getLength:int()
	
		local v:int;
		alGetBufferi(m_buffer, AL_SIZE, varptr(v));
		return v / bytespersample[m_sample.format];
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the number of samples per second we play the sound in, using the hertz unit.
	'// -------------------------------------------------------------------------------------------------------------
	method getFreq:int()
	
		local v:int;
		alGetBufferi(m_buffer, AL_FREQUENCY, varptr(v));
		return v;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the bit depth of the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method getBits:int()
	
		local v:int;
		alGetBufferi(m_buffer, AL_BITS, varptr(v));
		return v;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the channels of the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method getChannels:int()
	
		local v:int;
		alGetBufferi(m_buffer, AL_CHANNELS, varptr(v));
		return v;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Play the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method play()
	
		alSourcePlay(m_source);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Stop playing the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method stop()
	
		alSourceStop(m_source);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Pause the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method pause()
	
		alSourcePause(m_source);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Rewind the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method rewind()
	
		alSourceRewind(m_source);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the state of the sound.
	'// States include: AL_INITIAL, AL_PLAYING, AL_STOPPED, AL_PAUSED
	'// -------------------------------------------------------------------------------------------------------------
	method getState:int()
	
		Local v:int;
		alGetSourcei(m_source, AL_SOURCE_STATE, varptr(v));
		return v;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the playing position (the sample where we want to be positioned).
	'// -------------------------------------------------------------------------------------------------------------
	method setPosition(pos:int)
	
		alSourcei(m_source, AL_SAMPLE_OFFSET, pos);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Return the playing position (the sample where it's currently positioned).
	'// -------------------------------------------------------------------------------------------------------------
	method getPosition:int()
	
		local pos:int;
		alGetSourcei(m_source, AL_SAMPLE_OFFSET, varptr(pos));
		return pos;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the gain of the sound (using the dB unit).
	'// -------------------------------------------------------------------------------------------------------------
	method setGain(value:float = 1.0)
	
		alSourcef(m_source, AL_GAIN, 1.0);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Returns the gain of the sound (using the dB unit).
	'// -------------------------------------------------------------------------------------------------------------
	method getGain:float()
	
		local value:float;
		alGetSourcef(m_source, AL_GAIN, varptr(value));
		return value;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set the pitch of the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method setPitch(value:float = 1.0)
	
		alSourcef(m_source, AL_PITCH, 1.0);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Returns the pitch of the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method getPitch:float()
	
		local value:float;
		alGetSourcef(m_source, AL_PITCH, varptr(value));
		return value;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Set whether or not to loop the sound.
	'// -------------------------------------------------------------------------------------------------------------
	method setLoop(bool:byte = true)
	
		m_looping = bool;
		alSourcei(m_source, AL_LOOPING, bool);
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Returns whether or not the sound is being looped.
	'// -------------------------------------------------------------------------------------------------------------
	method getLoop:byte()
	
		return m_looping;
	
	end method
	
	'// -------------------------------------------------------------------------------------------------------------
	'// The path to the sound source.
	'// -------------------------------------------------------------------------------------------------------------
	field m_url:string;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// The OpenAL buffer.
	'// -------------------------------------------------------------------------------------------------------------
	field m_buffer:int;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// The OpenAL source.
	'// -------------------------------------------------------------------------------------------------------------
	field m_source:int;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// The source audio sample that is loaded into memory.
	'// -------------------------------------------------------------------------------------------------------------
	field m_sample:TAudioSample;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Information about the sound.
	'// -------------------------------------------------------------------------------------------------------------
	field m_format:int;
	field m_samples:byte ptr;
	field m_length:int;
	field m_freq:int;
	
	'// -------------------------------------------------------------------------------------------------------------
	'// Flag that determines whether or not the sound is being looped or not.
	'// -------------------------------------------------------------------------------------------------------------
	field m_looping:byte = false;	

end type
